/**
 * @file 路径处理的辅助方法，因为nodejs本身自带的path.js已经处理的比较完整，所以这里直接引入，但因为path.js需要考虑win和posix两种环境，这里引入的为posix部分的代码。
 * @see {@link https://github.com/nodejs/node/blob/master/lib/path.js}
 * @see {@link https://nodejs.org/dist/latest-v6.x/docs/api/path.html}
 * @module ke-url/path
 * @exports ke-url/path
 */

/**
 * 判断路径是否为绝对路径
 * @memberOf module:ke-url/path
 * @param {string} path 输入的路径，必须是字符串。
 * @returns {boolean}
 * @see {@link https://nodejs.org/dist/latest-v6.x/docs/api/path.html#path_path_isabsolute_path}
 */
export function isAbsolute(path): boolean {
	// ignore null, undefined, '', but except 0
	path = (typeof path === 'undefined' || path === null) ? '' : path + '';
	return path.length > 0 && path.charCodeAt(0) === 47;
}

function normalizeStringPosix(path, allowAboveRoot) {
	var res = '';
	var lastSlash = -1;
	var dots = 0;
	var code;
	for (var i = 0; i <= path.length; ++i) {
		if (i < path.length)
			code = path.charCodeAt(i);
		else if (code === 47/*/*/)
			break;
		else
			code = 47/*/*/;
		if (code === 47/*/*/) {
			if (lastSlash === i - 1 || dots === 1) {
				// NOOP
			} else if (lastSlash !== i - 1 && dots === 2) {
				if (res.length < 2 ||
					res.charCodeAt(res.length - 1) !== 46/*.*/ ||
					res.charCodeAt(res.length - 2) !== 46/*.*/) {
					if (res.length > 2) {
						const start = res.length - 1;
						var j = start;
						for (; j >= 0; --j) {
							if (res.charCodeAt(j) === 47/*/*/)
								break;
						}
						if (j !== start) {
							if (j === -1)
								res = '';
							else
								res = res.slice(0, j);
							lastSlash = i;
							dots = 0;
							continue;
						}
					} else if (res.length === 2 || res.length === 1) {
						res = '';
						lastSlash = i;
						dots = 0;
						continue;
					}
				}
				if (allowAboveRoot) {
					if (res.length > 0)
						res += '/..';
					else
						res = '..';
				}
			} else {
				if (res.length > 0)
					res += '/' + path.slice(lastSlash + 1, i);
				else
					res = path.slice(lastSlash + 1, i);
			}
			lastSlash = i;
			dots = 0;
		} else if (code === 46/*.*/ && dots !== -1) {
			++dots;
		} else {
			dots = -1;
		}
	}
	return res;
}

/**
 * 将一个路径进行规范化处理，并移除 `.` 和 `..` 部分。
 *
 * 与默认的node.js path.js不同的地方是，如果是空路径返回空字符串，而不是 `.`
 *
 * ```javascript
 * // 这不是一个绝对路径
 * normalize('bbb/ccc.html'); // bbb/ccc.html
 *
 * // 表示为一个绝对路径
 * normalize('/../a/./b/c/d/../e'); // /a/b/c/e
 *
 * // 当以 . 和 .. 开头时
 * normalize('../a/./b/c/d'); // ../a/b/c/d
 * normalize('./a/./b/c/d'); // a/b/c/d
 *
 * // 末尾的 / 也会保留
 * normalize('/a/b/c/'); // /a/b/c/
 * ```
 *
 * @memberOf module:ke-url/path
 * @param {string} path 输入的路径，必须是字符串。
 * @returns {string} 规范化处理过的路径值
 * @see {@link https://nodejs.org/dist/latest-v6.x/docs/api/path.html#path_path_normalize_path}
 */
export function normalize(path): string {
	// ignore null, undefined, '', but except 0
	path = (typeof path === 'undefined' || path === null) ? '' : path + '';

	if (path.length === 0)
		return '';

	const isAbsolute = path.charCodeAt(0) === 47/*/*/;
	const trailingSeparator = path.charCodeAt(path.length - 1) === 47/*/*/;

	// Normalize the path
	path = normalizeStringPosix(path, !isAbsolute);

	if (path.length === 0 && !isAbsolute)
		path = '';
	if (path.length > 0 && trailingSeparator)
		path += '/';

	if (isAbsolute)
		return '/' + path;
	return path;
}

//
/**
 * 以第一个参数为基础路径，拼接、替换后续的路径，并对合并出来的路径进行规范化处理。
 *
 * 后续的路径，如果是一个绝对路径（开头为 `/` ），则替换基础路径，否则则是拼接路径。
 *
 * ```javascript
 * // 基于/aa，替换/bb
 * // 输出 /bb
 * resolve('/aa', 'bb');
 *
 * // 基于/aa，替换/bb
 * // 输出 /bb
 * resolve('/aa', '/bb');
 *
 * // 基于/aa，拼接../bb，../cc
 * // 输出 /cc
 * resolve('/aa', '../bb', '../cc');
 * ```
 *
 * @memberOf module:ke-url/path
 * @param {string[]} paths 输入的多个路径值，其中第一个路径必须是一个有效的绝对路径。
 * @returns {string} 合并后的路径
 * @see {@link https://nodejs.org/dist/latest-v6.x/docs/api/path.html#path_path_resolve_paths}
*/
export function resolve(...paths): string {
	var resolvedPath = '';
	var resolvedAbsolute = false;
	// var cwd;

	for (var i = paths.length - 1; i >= -1 && !resolvedAbsolute; i--) {
		var path;
		if (i >= 0)
			path = arguments[i];
		// else {
		// 	if (cwd === undefined)
		// 		cwd = process.cwd();
		// 	path = cwd;
		// }

		// Skip empty entries
		if (path.length === 0) {
			continue;
		}

		resolvedPath = path + '/' + resolvedPath;
		resolvedAbsolute = path.charCodeAt(0) === 47/*/*/;
	}

	// At this point the path should be resolved to a full absolute path, but
	// handle relative paths to be safe (might happen when process.cwd() fails)

	// Normalize the path
	resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute);

	if (resolvedAbsolute) {
		if (resolvedPath.length > 0)
			return '/' + resolvedPath;
		else
			return '/';
	} else if (resolvedPath.length > 0) {
		return resolvedPath;
	} else {
		return '.';
	}
}
